﻿<script setup lang="ts" name="DynamicAnchor">
import useScrollPosition from '@/hooks/scrollPosition'
import useAffixPosition from '@/hooks/affixPosition'
import OtherAnchor from './Components/OtherAnchor.vue'
import useScrollListener from '@/hooks/scrollListener'
import { storeToRefs } from 'pinia'
import { usePublicStore } from '@/store/public/publicStore'
import { useSystemConfigStore } from '@/store/storage/systemConfigStore'
const route = useRoute()
const router = useRouter()

const systemConfigStore = useSystemConfigStore()
const { systemConfig } = storeToRefs(systemConfigStore)
useAffixPosition()

// 滚动行为
useScrollPosition(route)
const publicStore = usePublicStore()
const { affixTop } = storeToRefs(publicStore)

const getQuery = () => {
  let currentQuery: any = {}
  if (route.query) {
    if (route.query.key !== undefined) {
      currentQuery.key = route.query.key
    }
    if (route.query.anchor) {
      currentQuery.anchor = route.query.anchor
    }
    if (route.query.key === undefined && !route.query.anchor) {
      currentQuery = null
    }
  } else {
    currentQuery = null
  }
  return currentQuery
}
const currentQuery = getQuery()

const scrollHandler = (scrollTop) => {
  const scrollItems = document.querySelectorAll('.anchor')
  for (let i = scrollItems.length - 1; i >= 0; i--) {
    if (scrollTop >= (scrollItems[i] as HTMLElement).offsetTop - (scrollItems[0] as HTMLElement).offsetTop) {
      step.value = i
      break
    }
  }
  initAnchorTop(scrollTop)
}
const anchorTop = ref('')
const initAnchorTop = (scrollTop) => {
  const scrollItems = document.querySelectorAll('.anchor')
  const anchorWrap = document.querySelector('.anchor-wrap') as HTMLElement
  const anchorNav = document.querySelector('.fixed-anchor') as HTMLElement
  const startTop = anchorWrap.offsetTop
  const endTop = (scrollItems[scrollItems.length - 1] as HTMLElement).offsetTop + (scrollItems[scrollItems.length - 1] as HTMLElement).offsetHeight - anchorNav.offsetHeight - startTop
  if (scrollTop < startTop) {
    anchorTop.value = (affixTop.value + startTop - scrollTop).toString()
  } else if (scrollTop >= startTop && scrollTop <= endTop) {
    anchorTop.value = affixTop.value.toString()
  } else {
    anchorTop.value = (affixTop.value + endTop - scrollTop).toString()
  }
}

useScrollListener(route, scrollHandler)

const step = ref(0)
const jumpAnchor = (value) => {
  step.value = value
  document.querySelector('.anchor-' + value).scrollIntoView({ behavior: 'smooth', block: 'start' })
}

const jumpOtherAnchor = (value) => {
  document.querySelector(value).scrollIntoView({ behavior: 'smooth', block: 'start' })
}
const jumpOtherPathAnchor = (value) => {
  router.push('/Functions/DynamicAnchor/RichTextAnchor?anchor=' + value)
}

onMounted(() => {
  if (currentQuery && currentQuery.anchor) {
    setTimeout(() => {
      if (currentQuery.anchor.includes('.other-anchor-')) {
        document.querySelector(currentQuery.anchor).scrollIntoView({ behavior: 'smooth', block: 'start' })
      } else {
        document.querySelector('.anchor-' + currentQuery.anchor).scrollIntoView({ behavior: 'smooth', block: 'start' })
      }
    }, 500)
  }
})
</script>

<template>
  <el-space :size="systemConfig.space" fill direction="vertical">
    <el-card shadow="never" class="anchor-wrap no-border no-radius">
      <div class="anchor-panel">
        <el-card class="fixed-anchor" :style="{ top: anchorTop !== '' ? (anchorTop + 'px') : '' }">
          <div class="anchor-list">
            <div class="active-line" :style="{ top: step * 32 + 'px' }"></div>
            <div class="item-anchor" :class="step === 0 ? 'is-active' : ''" @click="jumpAnchor(0)"><span>清风</span></div>
            <div class="item-anchor" :class="step === 1 ? 'is-active' : ''" @click="jumpAnchor(1)"><span>细雨</span></div>
            <div class="item-anchor" :class="step === 2 ? 'is-active' : ''" @click="jumpAnchor(2)"><span>独木桥</span></div>
            <div class="item-anchor" :class="step === 3 ? 'is-active' : ''" @click="jumpAnchor(3)"><span>凭栏映婀娜</span></div>
          </div>
        </el-card>
        <div class="anchor anchor-0">
          <p>散尽离愁，携得清风出画楼。————晏几道《采桑子·高吟烂醉淮西月》</p>
          <p>当前锚点：anchor-0</p>
          <el-alert title="实现vue中锚点跳转页面不刷新；实现富文本中的锚点正常跳转；实现页面间、组件间的锚点跳转。" type="success" :closable="false" show-icon />
        </div>
        <div class="anchor anchor-1">
          <p>海棠不惜胭脂色，独立蒙蒙细雨中。————陈与义《春寒》</p>
          <p>当前锚点：anchor-1</p>
          <el-button type="primary" plain @click="jumpOtherAnchor('.other-anchor-0')">跳转到本页面组件内锚点other-anchor-0</el-button>
        </div>
        <div class="anchor anchor-2">
          <p>瘦藤忽梦寻梅去，袅袅寒溪独木桥。————程公许《除夕和唐人张继张佑即事四绝句·经世无才慕管萧》</p>
          <p>当前锚点：anchor-2</p>
          <el-button type="primary" plain @click="jumpOtherPathAnchor('a2')">
            跳转到
            <strong>富文本锚点页面的细雨锚点anchor-a2</strong>
            位置
          </el-button>
        </div>
        <div class="anchor anchor-3">
          <p>醉酒不知归，凭栏映婀娜。</p>
          <p>当前锚点：anchor-3</p>
          <el-button type="primary" plain @click="jumpOtherPathAnchor('.other-anchor-1')">
            跳转到
            <strong>富文本锚点页面的组件内other-anchor-1锚点</strong>
            位置
          </el-button>
        </div>
      </div>
      <other-anchor></other-anchor>
    </el-card>
  </el-space>
</template>

<style scoped lang="scss">
.el-space {
  width: 100%;
  padding: var(--el-space) var(--el-space) 0;
}

.no-border {
  border: none;
}

.no-radius {
  border-radius: 0;
}

.anchor-panel {
  .anchor {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;

    .el-button,
    .el-alert {
      margin-top: 20px;
    }
  }

  .anchor-0 {
    height: 80vh;
    background: var(--el-color-primary-light-9);
  }

  .anchor-1 {
    height: 40vh;
    background: var(--el-color-success-light-9);
  }

  .anchor-2 {
    height: 60vh;
    background: var(--el-color-warning-light-9);
  }

  .anchor-3 {
    height: 80vh;
    background: var(--el-color-danger-light-9);
  }
}

.fixed-anchor {
  position: fixed;
  right: calc(var(--el-space) * 2);
  z-index: 1000;
  transition: none;

  .anchor-list {
    position: relative;

    &::before {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      width: 2px;
      background: var(--el-fill-color-darker);
      content: ''
    }

    .active-line {
      position: absolute;
      left: 0;
      z-index: 2;
      width: 2px;
      height: 32px;
      background-color: var(--el-color-primary);
      transition: top 0.28s 0.28s linear;
    }

    .item-anchor {
      span {
        display: block;
        height: 32px;
        padding: 0 20px;
        line-height: 32px;
        cursor: pointer;
      }

      &:hover {
        span {
          color: var(--el-color-primary);
        }
      }

      &.is-active {
        span {
          color: var(--el-color-primary);
        }
      }
    }
  }
}
</style>
